package cn.edu.neu.lab603.cloudeval.monitor

import cn.edu.neu.lab603.cloudeval.CloudEval
import cn.edu.neu.lab603.cloudeval.entity.{CloudTask, VirtualMachine}
import cn.edu.neu.lab603.des.{SimMetric, SimMonitor}

import scala.collection.mutable
import scala.collection.mutable.ListBuffer

/** 统计 Cloudlet 的连续运行时间。
  *
  * @param eta 能忍受的最小长度
  * @author yfwz100
  */
class CloudletLiveTimeMonitor(private val eta: Double = 10) extends SimMonitor[CloudEval] {

  protected val stats = new mutable.HashMap[Long, mutable.ListBuffer[Long]]

  /** 获得整体的统计量 */
  def getOverallFrustrationMetric(alpha: Double = 300) = new SimMetric[Double] {

    def getFr(a: Double, b: Double): Double = {
      val m = (a + b) / 2
      val p = math.log(1 + m / alpha)
      val ab = a + b
      math.pow(math.pow(a / ab, -p) + math.pow(b / ab, -p), -p)
    }

    override def getCurrentValue: Double = if (stats.nonEmpty) stats.values.map { segments =>
      if (segments.size > 1) {
        (1 until segments.size).map(i => getFr(segments(i - 1), segments(i))).sum / (segments.size - 1)
      } else 0.0
    }.sum
    else 0.0
  }

  /** 获取动荡的指标 */
  def getAverageFrustrationMetric(alpha: Double = 300) = new SimMetric[Double] {

    def getFr(a: Double, b: Double): Double = {
      val m = (a + b) / 2
      val p = math.log(1 + m / alpha)
      val ab = a + b
      math.pow(math.pow(a / ab, -p) + math.pow(b / ab, -p), -p)
    }

    override def getCurrentValue: Double = if (stats.nonEmpty) stats.values.map { segments =>
      if (segments.size > 1) {
        (1 until segments.size).map(i => getFr(segments(i - 1), segments(i))).sum / (segments.size - 1)
      } else 0.0
    }.sum / stats.size
    else 0.0
  }

  override def isMatch(context: CloudEval): Boolean = context.getCurrentTask match {
    case _: VirtualMachine.MigrationPostCopyEvent => true
    case _: CloudTask.FinishEvent => true
    case _ => false
  }

  override def before(context: CloudEval): Unit = {}

  override def after(context: CloudEval): Unit = {
    val cloudlet = context.getCurrentTask match {
      case t: VirtualMachine.MigrationPostCopyEvent =>
        t.vm.getCloudlet
      case t: CloudTask.FinishEvent =>
        t.cloudlet
    }
    val execList = stats.getOrElseUpdate(cloudlet.cloudletNo, ListBuffer.empty)
    if (execList.isEmpty) {
      if (cloudlet.getCursor > 0)
        execList += cloudlet.getCursor
    } else {
      val preSum = execList.sum
      if (cloudlet.getCursor > preSum) {
        execList += cloudlet.getCursor - preSum
      }
    }
  }

  /** 获得当前的统计量。 */
  def getStats: Map[Long, List[Long]] = stats.mapValues(_.result).toMap

}
